﻿using System;
using System.Diagnostics;
using System.Reflection;
using System.Xml;
using System.Xml.Linq;
using AzureStorageMapper.Criterias.TableStorage;
using AzureStorageMapper.TableStorage;
using AzureStorageMapper.TableStorage.Attributes;
using NUnit.Framework;
using System.Threading;
using System.Collections.Generic;
using AzureStorageMapper.TableStorage.Utils;
using System.Text;
using System.Web;

namespace AzureStorageMapper.Tests.TableStorage
{
    [TestFixture]
    public class Sample
    {
        [Test]
        public void UriEncodeTest()
        {
            string path = "(abc ge '123') and (def lt 20)";

            Console.WriteLine(HttpUtility.UrlEncode(path));
            Console.WriteLine(HttpUtility.UrlPathEncode(path));
        }

        private static XNamespace def = @"http://www.w3.org/2005/Atom";
        private static XNamespace d = @"http://schemas.microsoft.com/ado/2007/08/dataservices";
        private static XNamespace m = @"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";

        private object GetPropertyValue(string strVal, Type type)
        {
            if (type == typeof(string))
                return strVal;
            if (type == typeof(DateTime))
                return XmlConvert.ToDateTime(strVal, XmlDateTimeSerializationMode.RoundtripKind);
            if (type == typeof(byte[]))
                return UTF8Encoding.UTF8.GetBytes(strVal);
            else
            {
                MethodInfo praseMethod = type.GetMethod("Parse", new Type[] { typeof(string) });
                return praseMethod.Invoke(type, new object[] { strVal });
            }
        }

        //[Test]
        public void AddSomeSampleData()
        {
            //SampleTableModel.CreateTable<SampleTableModel>();
            //Trace.TraceInformation("Create table ... sleep for 10 sec ... ");
            //Thread.Sleep(TimeSpan.FromSeconds(10));

            //for (int i = 2; i < 7; i++)
            //{
            //    SampleTableModel s = new SampleTableModel("default", Guid.NewGuid().ToString());
            //    s.ColumnOne = "col 1 - " + i;
            //    s.ColumnTwo = i;
            //    s.ColumnThree = 10000 + i;

            //    s.Save();

            //    Trace.TraceInformation("Save one ... sleep for 5 sec ... ");
            //    Thread.Sleep(TimeSpan.FromSeconds(5));
            //}

            //SampleTableModel.GetEntities<SampleTableModel>();

            List<SampleTableModel> results = new List<SampleTableModel>();
                        
            XDocument xdoc = XDocument.Load(@"C:\Users\xiaowu\Desktop\fff.xml");
            var entries = xdoc.Root.Elements(def + "entry");

            List<string> fields = new List<string>();
            TableInfo tInfo = TableUtilities.GetTableInfo(typeof(SampleTableModel));
            foreach (var item in tInfo.Columns)
            {
                fields.Add(item.Name);
            }

            foreach (var item in entries)
            {
                ConstructorInfo ci = typeof(SampleTableModel).GetConstructor(new Type[] { typeof(string), typeof(string) });
                SampleTableModel entry = (SampleTableModel)ci.Invoke(new object[] { "", "" });

                foreach (var ti in tInfo.Columns)
                {
                    XElement el = item.Element(def + "content")
                                       .Element(m + "properties")
                                       .Element(d + ti.Name);

                    XAttribute nullAttr = el.Attribute(m + "null");

                    PropertyInfo[] pInfo = typeof(SampleTableModel).GetProperties();
                    foreach (var pi in pInfo)
                    {
                        object columnName;
                        TableColumn tc = TableUtilities.GetColumnInfo(pi, out columnName);
                        if (pi.Name.Equals(ti.Name, StringComparison.InvariantCultureIgnoreCase)
                            || ti.Name.Equals(tc.Name, StringComparison.InvariantCultureIgnoreCase))
                        {
                            try
                            {
                                object propVal = null;
                                if (nullAttr == null)
                                    propVal = GetPropertyValue(el.Value, ti.ColumnType);

                                pi.SetValue(entry, propVal, null);
                                break;
                            }
                            catch (FormatException fe)
                            {
                                Trace.TraceError("Failed to convert value for '{0}',  raw value : '{1}'\n{2}", ti.Name, el.Value, fe.StackTrace);
                            }
                        }
                    }
                }

                XElement pel = item.Element(def + "content")
                                       .Element(m + "properties")
                                       .Element(d + "PartitionKey");
                PropertyInfo propPartKey = typeof(SampleTableModel).GetProperty("PartitionKey");
                propPartKey.SetValue(entry, pel.Value, null);

                XElement rel = item.Element(def + "content")
                                       .Element(m + "properties")
                                       .Element(d + "RowKey");
                PropertyInfo propRowKey = typeof(SampleTableModel).GetProperty("RowKey");
                propRowKey.SetValue(entry, rel.Value, null);

                results.Add(entry);
            }

            Assert.AreEqual(10, results.Count);
        }

        [Test]
        public void NullEnumTest()
        {
            TableContext<SampleTableModel> tc = new TableContext<SampleTableModel>();
            var v = tc.FindEntity("", "dd");
            Assert.IsNull(v);
        }

        [Test]
        public void DateTimeTest()
        {
            DateTime date = DateTime.Now;
            string dateStr = XmlConvert.ToString(date, XmlDateTimeSerializationMode.RoundtripKind);
            Trace.TraceInformation("---- {0}", dateStr);

            DateTime date2 = XmlConvert.ToDateTime(dateStr, XmlDateTimeSerializationMode.RoundtripKind);
            DateTime date3 = DateTime.Parse(dateStr);

            Assert.AreEqual(date, date2);
            Assert.AreEqual(date, date3);
        }

        [Test]
        public void TypeTest()
        {
            Assert.AreEqual(typeof(double), typeof(Double));
            Assert.AreEqual(typeof(int), typeof(Int32));
            Assert.AreEqual(typeof(long), typeof(Int64));
            Assert.AreEqual(typeof(bool), typeof(Boolean));
            Assert.AreEqual(typeof(string), typeof(String));
            Assert.AreEqual(typeof(byte), typeof(Byte));
            Assert.AreEqual(typeof(byte[]), typeof(Byte[]));
        }

        //[Test]
        public void Test()
        {
            XDocument doc = XDocument.Load(@"C:\Users\shrimpy\Documents\Visual Studio 2010\Projects\AzureStorageMapper\AzureStorageMapper.Tests\TableStorage\Sample.xml");

            XNamespace def = @"http://www.w3.org/2005/Atom";
            XNamespace d = @"http://schemas.microsoft.com/ado/2007/08/dataservices";
            XNamespace m = @"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";

            foreach (XElement item2 in doc.Descendants(d + "PartitionKey"))
            {
                XAttribute att = item2.Attribute(m + "null");
                if (att != null)
                    Trace.TraceInformation("--->1 Null : '{0}'", att.Value);

                Trace.TraceInformation("===> PartitionKey: '{0}'", item2.Value);
            }

            foreach (XElement item2 in doc.Descendants(d + "Address"))
            {
                XAttribute att = item2.Attribute(m + "null");
                if (att != null)
                    Trace.TraceInformation("--->2 Null : '{0}'", att.Value);

                Trace.TraceInformation("===> Address: '{0}'", item2.Value);
            }

            foreach (XElement item2 in doc.Descendants(d + "Name"))
            {
                XAttribute att = item2.Attribute(m + "null");
                if (att != null)
                    Trace.TraceInformation("--->3 Null : '{0}'", att.Value);

                Trace.TraceInformation("===> Name: '{0}'", item2.Value);
            }

            foreach (var str in new string[] { "PartitionKey", "RowKey", "Address", "CustomerSince", "Name" })
            {
                XElement el = doc.Root.Element(def + "entry")
                                      .Element(def + "content")
                                      .Element(m + "properties")
                                      .Element(d + str);

                XAttribute att = el.Attribute(m + "null");
                Trace.TraceInformation("---> E '{0}' ... '{1}'", el.Value, (att == null ? "" : att.Value));
            }

            Type type = typeof(DateTime);
            MethodInfo praseMethod = type.GetMethod("Parse", new Type[] { typeof(string) });
            object oo = praseMethod.Invoke(type, new object[] { "2008-10-01T15:25:05.2852025Z" });
            Trace.TraceInformation("----> Time '{0}'", oo);


            /*
            string[] result1 = content.Split(new string[] { @"<content type=""application/xml"">", "</content>" }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var item in result1)
            {
                string sample = item.Trim();
                if (sample.StartsWith("<m:properties>"))
                {
                    Trace.TraceInformation("---> '{0}'", sample);
                    XDocument doc = XDocument.Parse(sample);

                    foreach (XElement item2 in doc.Descendants("d:PartitionKey"))
                    {
                        Trace.TraceInformation("===> '{0}'", item2.Value);
                    }
                }
            }
            */
        }
        
        [TableModel(Name = "SampleQueryTests")]
        internal class SampleTableModel : TableEntity
        {
            [TableColumn]
            public string ColumnOne { get; set; }

            [TableColumn(Name = "Column2")]
            public int ColumnTwo { get; set; }

            [TableColumn]
            public long ColumnThree { get; set; }

            public SampleTableModel(string partitionKey, string rowKey)
                : base(partitionKey, rowKey)
            {
            }
        }
    }
}
